﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace DigitalImage.softLib {
    public class CRasterRegion:IComparable<CRasterRegion> {
        public static readonly CRasterRegion spaceRegion=new CRasterRegion();
 
        public String Tag=null;
        public int regId=0;
        public List<Point> points=new List<Point>();

        public Boolean momentiOdredjeni=false;
        public int n=0;  // ukupan broj tacaka

        public double c20=0;
        public double c11=0;
        public double c02=0;

        public int minX=int.MaxValue;
        public int maxX=0;
        public int minY=int.MaxValue;
        public int maxY=0;

        #region osnovne statisticke osobine regiona
        public double xM=0;
        public double yM=0;
        public double theta=0;
        public double eccentricity=0;
        public double majorAxisLength=0;
        public double minorAxisLength=0;
        #endregion

        public void odrediMomente() {
            xM=0;
            yM=0;
            theta=0;
            eccentricity=0;
            majorAxisLength=0;
            minorAxisLength=0;
            n=points.Count;
            foreach(Point pp in points) {
                xM+=pp.X;
                yM+=pp.Y;

                // odredi "minimum bounding box" regiona
                if(pp.X<minX)
                    minX=pp.X;
                if(pp.X>maxX)
                    maxX=pp.X;
                if(pp.Y<minY)
                    minY=pp.Y;
                if(pp.Y>maxY)
                    maxY=pp.Y;
            }
            xM=xM/n;
            yM=yM/n;
            foreach(Point pp in points) {
                c20+=(pp.X-xM)*(pp.X-xM);
                c11+=(pp.X-xM)*(pp.Y-yM);
                c02+=(pp.Y-yM)*(pp.Y-yM);
            }
            // sad imamo vrednosti covariance matrix
            // c20 c11
            // c11 c02
            // odrediti karakteristicne vrednosti
            double a=1;
            double b=-(c20+c02);
            double c=c20*c02-c11*c11;
            double D=b*b-4*c;
            double alfa1=0;
            double alfa2=0;
            if(D>0) {
                D=Math.Sqrt(D);
                alfa1=(-b+D)/2*a;
                alfa2=(-b-D)/2*a;
                double temp1=Math.Max(alfa1, alfa2);
                double temp2=Math.Min(alfa1, alfa2);
                alfa1=temp1;
                alfa2=temp2;
                if(alfa1!=0)
                    eccentricity=alfa2/alfa1;
                majorAxisLength=alfa1;
                minorAxisLength=alfa2;
            }
            theta=0.5*Math.Atan2(2*c11, (c20-c02));
        }

        public byte[,] odrediSliku() {
            if(!momentiOdredjeni)
                odrediMomente();

            int height=maxY-minY+1;
            int width=maxX-minX+1;

            byte[,] retVal=new byte[height, width];
            for(int i=0;i<height;i++) {
                for(int j=0;j<width;j++) {
                    retVal[i, j]=255;
                }
            }

            foreach(Point p in points) {
                retVal[p.Y-minY, p.X-minX]=0;
            }

            return retVal;
        }

        public byte[,] odrediNSliku() {
            if(!momentiOdredjeni)
                odrediMomente();

            List<Point> nPoints=new List<Point>();

            double ugao=Math.PI/2-Math.Abs(theta);
            foreach(Point p in points) {
                double nX=Math.Cos(ugao)*(p.X-xM)-Math.Sin(ugao)*(p.Y-yM)+xM;
                double nY=Math.Sin(ugao)*(p.X-xM)+Math.Cos(ugao)*(p.Y-yM)+yM;

                nPoints.Add(new Point((int)nX, (int)nY));
            }

            CRasterRegion nRegion=new CRasterRegion();
            nRegion.points=nPoints;

            return nRegion.odrediSliku();
        }

        public class RComparer:IComparer<CRasterRegion> {
            #region IComparer<RasterRegion> Members
            public int Compare(CRasterRegion a, CRasterRegion b) {
                return a.minX.CompareTo(b.minX);
            }

            #endregion
        }


        #region IComparable<CRasterRegion> Members

        public int CompareTo(CRasterRegion other) {
            return (int)(xM-other.xM);
        }

        #endregion
    }

    class CRegionListYComparation:Comparer<List<CRasterRegion>> {

        public override int Compare(List<CRasterRegion> x, List<CRasterRegion> y) {
            if(y.Count==0)
                return 1;
            if(x.Count==0)
                return -1;
            if(x[0].yM>=y[0].yM) {
                return 1;
            } else {
                return -1;
            }
        }
    }
}
